home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
201-220
/
scopedisk215
/
update
/
update.asm
< prev
next >
Wrap
Assembly Source File
|
1995-03-19
|
61KB
|
1,338 lines
*****************************************************************
* *
* Program Name: Update *
* Version: 1.0 *
* Change History: 11-Nov-87 Initial Program Version *
* *
* Copyright (c) 1987 - Bob Rakosky *
* *
* USAGE: *
* Update [FROM] obj1 [obj2 ... obj12] TO dir [SINCE mfile] *
* *
* where obj1 ... obj12 are either files or directories, *
* (with or without wildcards) *
* dir is the output directory name *
* mfile is a file name *
* *
* Will copy all files specified (or in directories specified) *
* to dir IF the file's datestamp is later than the datestamp *
* for file mfile (if specified) or later than the datestamp *
* of the corresponding-named file in dir2 (if mfile not *
* specified). In the latter case, if the corresponding file *
* does not exist in the output directory, the file is copied. *
* *
* NOTES *
* This program REQUIRES the use of ARP.library, which *
* must be in your libs: logical directory. If the *
* library is not present, the program will issue an error *
* message and exit. *
* *
*****************************************************************
include "exec/types.i"
include "exec/memory.i"
include "libraries/dos.i"
include "libraries/dosextens.i"
include "arpbase.i"
*---------------------------------------------------------------*
* Some commonly used macros *
*---------------------------------------------------------------*
XTERN MACRO ;XTERN <reference>
XREF _LVO\1 ; Adds the '_LVO' prefix to it.
ENDM
CALL MACRO ;call < routine(register) >
jsr _LVO\1 ; Adds the '_LVO' prefix to the routine name.
ENDM
*---------------------------------------------------------------*
* Equates *
*---------------------------------------------------------------*
Absbase EQU 4
*---------------------------------------------------------------*
* External references *
*---------------------------------------------------------------*
XTERN OpenLibrary
XTERN CloseLibrary
XTERN AllocMem
XTERN FreeMem
XTERN Output
XTERN Write
XTERN Read
XTERN Lock
XTERN UnLock
XTERN ParentDir
XTERN Examine
XTERN ExNext
XTERN Open
XTERN Close
XTERN IoErr
XTERN DeviceProc
*---------------------------------------------------------------*
* Buffer Size for Read/Write Buffer *
*---------------------------------------------------------------*
RW_BUFS EQU $4000 ;16 K Buffer size
*****************************************************************
* Main Program *
*****************************************************************
start movem.l d1-d7/a0-a6,-(a7) ;save entry regs
bsr init ;perform initialization
tst.l d0 ;Q. Good Return?
bne exit ;A. no - quit now
bsr parse ;Parse the command line
tst.l d0 ;Q. Good return?
bne exit ;A. No - exit
tst.l sinfil(a5) ;Q. SINCE file name specified?
beq.s main010 ;A. no since file - bypass
move.l sinfil(a5),a0 ;address of SINCE file name
bsr getfib ;get datestamp of file
tst.l d0 ;Q. Good Return?
beq.s main010 ;A. Yes - continue
*---------------------------------------------------------------*
* Unable to locate/examine 'SINCE' file *
*---------------------------------------------------------------*
lea nosinm(pc),a0
move.l a0,d2 ;address message
move.l #nosinml,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6)
moveq.l #20,d0 ;set bad return code
bra exit ;and quit
main010:
lea fib(a5),a1 ;point to fib
lea fib_DateStamp(a1),a0 ;point to Datestamp
lea cmpdate(a5),a1 ;save 'since date' here
*---------------------------------------------------------------*
* The datestamp for comparison will be one tick less *
* than that of the 'SINCE' file. *
*---------------------------------------------------------------*
move.l (a0)+,(a1)+ ;move datestamp days to compare area
move.l (a0)+,(a1)+ ;move datestamp minutes to compare area
move.l (a0),d0 ;get ticks
subq.l #1,d0 ;decrement by 1
move.l d0,(a1) ;move ticks to compare area
*---------------------------------------------------------------*
* Verify Output specified is a directory *
*---------------------------------------------------------------*
move.l todir(a5),a0 ;address of output directory name
bsr getfib ;get file info
tst.l d0 ;Q. Good Return?
beq.s main020 ;A. Yes - continue
move.l stdout(a5),d1 ;msg file
lea noout(pc),a0
move.l a0,d2 ;address message
move.l #nooutl,d3 ;length of it.
move.l a4,a6 ;DOSBase into a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
moveq.l #20,d0 ;set return code
bra.s exit ;and quit
main020:
lea fib(a5),a0 ;point to file info block
move.l fib_DirEntryType(a0),d0 ;file or directory indicator
bpl.s main030 ;> 0 ==> directory - continue
*---------------------------------------------------------------*
* TO specified is not a directory *
*---------------------------------------------------------------*
move.l stdout(a5),d1 ;msg file
lea notdir(pc),a0
move.l a0,d2 ;address message
move.l #notdirl,d3 ;length of it.
move.l a4,a6 ;DOSBase into a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
moveq.l #20,d0 ;set return code
bra.s exit ;and quit
main030:
*---------------------------------------------------------------*
* copy target directory name to buffer and mark end *
*---------------------------------------------------------------*
move.l todir(a5),a0 ;path name
lea outbuf(a5),a1 ;buffer area
1$: move.b (a0)+,(a1)+ ;next char
bne 1$ ;loop until end of string
lea -2(a1),a1 ;back up to last non-blank character
move.b (a1)+,d0 ;examine last character
cmp.b #':',d0 ;Q. Last character colon ?
beq.s 2$ ;A. yes - don't append slash
move.b #'/',(a1)+ ;A. no - append a slash
2$:
move.l a1,outfnam(a5) ;concat output file name here
*---------------------------------------------------------------*
* loop and process all arguments *
*---------------------------------------------------------------*
move.w argc(a5),d7 ;number of arguments
ext.l d7
move.l #2,d6 ;reduce by at least 1 (for target)
; plus 1 to make relative to 0
tst.l sinfil(a5) ;Q. Was 'since' option specified?
beq.s main040 ;A. No - bypass adjustment
addq.l #1,d6 ;A. Yes - one less input arguments
main040:
sub.l d6,d7 ;adjust loop counter
clr.l d6 ;index value into d6
lea argv(a5),a4 ;point to first arg
main050:
move.l 0(a4,d6.w),a0 ;pick up next argument
bsr procarg ;process input argument
tst.l d0 ;Q. Good return?
bne.s exit ;A. No - quit now
addq.w #4,d6 ;increment index
dbra d7,main050 ;loop on
*---------------------------------------------------------------*
* End of processing loop - set good return code and exit *
*---------------------------------------------------------------*
clr.l d0 ;set good return code and exit
exit: move.l d0,-(a7) ;save return code
bsr cleanup ;free resources
move.l (a7)+,d0 ;restore return code
movem.l (a7)+,d1-d7/a0-a6 ;restore other regs
rts ;return to caller
PAGE
*****************************************************************
* Section Name: init *
* Function: Performs initial housekeeping *
* Entry Registers: a0 - command line string *
* d0 - command line length *
* Exit Registers: d0 - return code (0 = success) *
* a5 - work area address *
*****************************************************************
init:
move.l a0,a3 ;save command line
move.l d0,d3 ; address and length
*---------------------------------------------------------------*
* Open DOS Library *
*---------------------------------------------------------------*
move.l Absbase,a6 ;find library
lea dosname(pc),a1 ;point to libname string
moveq #33,d0 ;version at least 1.2 (or higher)
* libbase = OpenLibrary(libname,version);
* d0 a1 d0
CALL OpenLibrary(a6) ;open dos library
movea.l d0,a4 ;save dos pointer for later use
beq init_err ;OpenLibrary failed, can't tell user - just exit
*---------------------------------------------------------------*
* Get Std Output File Handle *
*---------------------------------------------------------------*
movea.l a4,a6 ;DosBase into a6
* stdout = Output();
* d0
CALL Output(a6) ;get file handle for screen
move.l d0,d4 ;save filehandle
*---------------------------------------------------------------*
* Allocate work area *
*---------------------------------------------------------------*
move.l #wk_lgth,d0 ;length in d0
move.l #MEMF_CLEAR,d1 ;type in d1
move.l Absbase,a6
* area = AllocMem(size,flags);
* d0 d1 d0
CALL AllocMem(a6) ;call AllocMem
movea.l d0,a5 ;address work area
bne.s init010 ;we now have a work area
*---------------------------------------------------------------*
* Allocate failed - tell user and exit *
*---------------------------------------------------------------*
move.l d4,d1 ;Std Output file handle
beq.s init_err ;couldn't get screen handle - just exit
lea nomem(pc),a0
move.l a0,d2 ;address message
move.l #nomeml,d3 ;length of it.
move.l a4,a6 ;DOSBase into a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
bra.s init_err ;and leave
*---------------------------------------------------------------*
* We now have a work area *
*---------------------------------------------------------------*
init010:
move.l a4,dosaddr(a5) ;save dos address
move.l a3,cmdline(a5) ;address of command line
move.l d3,cmdlen(a5) ;length of command line
move.l d4,stdout(a5) ;save address of Std Output
*---------------------------------------------------------------*
* Open ARP Library *
*---------------------------------------------------------------*
move.l Absbase,a6 ;find library
lea arpname(pc),a1 ;point to libname string
moveq #ArpVersion,d0 ;version at least 1.2 (or higher)
* libbase = OpenLibrary(libname,version);
* d0 a1 d0
CALL OpenLibrary(a6) ;open dos library
move.l d0,arpbase(a5) ;save base pointer for later use
bne init020 ;OpenLibrary OK - initialization complete
*---------------------------------------------------------------*
* Unable to open Arp Library *
*---------------------------------------------------------------*
move.l stdout(a5),d1 ;msg file
lea noarp(pc),a0
move.l a0,d2 ;address message
move.l #noarpl,d3 ;length of it.
move.l a4,a6 ;DOSBase into a6
* Write(file,data,length);
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
bra.s init_err ;and leave
*---------------------------------------------------------------*
* Initialization Complete *
*---------------------------------------------------------------*
init020:
clr.l d0 ;set good return code
rts ; return to sender
*---------------------------------------------------------------*
* Initialization Error *
*---------------------------------------------------------------*
init_err:
moveq.l #20,d0 ;set error return code
rts
PAGE
*****************************************************************
* Section Name: parse *
* Function: Parse the command line *
* Entry Data: cmdline - address of command line *
* cmdlen - length of command line *
* NOTE - relative to ZERO *
* Exit Data: d0 - return code (0 = success, 20 = error) *
* argc - number of parameters specified *
* argv - a table of pointers to the 'words' *
* *
*****************************************************************
parse:
movea.l cmdline(a5),a0 ;point to command line
move.l cmdlen(a5),d0 ;length of command line
lea cmdpr(pc),a1 ;help string
lea argv(a5),a2 ;arg array
lea templ(pc),a3 ;command template
move.l arpbase(a5),a6 ;arpbase
* argc = GADS(cmdline,cmdlength,help,&argv[0],template);
* d0 a0 d0 a1 a2 a3
CALL GADS(a6) ;parse the command line
move.w d0,argc(a5) ;store arg count
ble.s pars_err ;==-1 -> parse error
;==0 parsed ok but no arguments
*---------------------------------------------------------------*
* Successful parse of command line *
*---------------------------------------------------------------*
clr.l d0 ;good return code
rts ;return
*---------------------------------------------------------------*
* Unexpected error in parsing routine - should never happen *
*---------------------------------------------------------------*
pars_err:
lea ferrm(pc),a0
move.l a0,d2 ;Set up and write err msg to console
move.l #ferrml,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,length);
* d1 d2 d3
CALL Write(a6)
moveq.l #20,d0 ;set bad return code
rts ;and return
PAGE
*****************************************************************
* Section Name: cleanup *
* *
* Function: Frees all system resources acquired *
* *
* Entry Data: a5 - Address of global work area (if it *
* exists *
* *
* Exit Data: none *
* *
*****************************************************************
cleanup:
move.l a5,d0 ;address of work area
beq.s cleanret ; none - nothing to clean up
move.l databuf(a5),d0 ;Q. do we have a read/write buffer?
beq.s cln010 ;A. NO - bypass freeing it
move.l d0,a1 ;address of area to free
move.l #RW_BUFS,d0 ;size of area to free
move.l Absbase,a6
* FreeMem(area,size);
* a1 d0
CALL FreeMem(a6)
cln010:
move.l arpbase(a5),d0 ;Q. Is ARP library open?
beq.s cln020 ;A. no - don't close it
move.l d0,a1 ;address of arp base
move.l Absbase,a6
* CloseLibrary(libbase);
* d0
CALL CloseLibrary(a6)
cln020:
move.l a5,a1 ;address of work area
move.l #wk_lgth,d0 ;length of work area
move.l Absbase,a6 ;exec library
* FreeMem(area,size);
* a1 d0
CALL FreeMem(a6) ;free work area
cleanret:
rts ;return to caller
PAGE
*****************************************************************
* Section Name: procarg *
* *
* Function: Processes a single input argument from the *
* command-line *
* *
* Entry Data: a0 - pointer to argument, which is either *
* a file or directory (with/without *
* wild-cards *
* *
* Exit Data: d0 - return code (0 = success) *
* *
*****************************************************************
procarg:
move.l a0,-(a7) ;push passed argument
move.l #128,d0
lea anchor(a5),a0 ;point to f/n search anchor
move.l d0,AP_LENGTH(a0) ;length of fname
move.l (a7)+,d0 ;pop passed argument
move.l arpbase(a5),a6 ;ARP base
* rc = FindFirst(pattern,chain)
* d0 d0 a0
CALL FindFirst(a6)
tst.l d0 ;Q. Good Return?
bne.s parg_err ;A. No - error exit
parg010:
lea anchor(a5),a1 ;point to search anchor
lea AP_INFO(a1),a0 ;point to internal FIB
move.l fib_DirEntryType(a0),d0 ;file or directory indicator
bpl parg020 ;> 0 ==> directory - continue
*---------------------------------------------------------------*
* entry is a file *
*---------------------------------------------------------------*
lea fname(a5),a1 ;point to full path name
;note - a0 still points to fib
bsr dofile ;process input file
tst.l d0 ;Q. Good return?
bne.s parg_err ;A. no - quit
bra.s parg030 ;continue with next in chain
parg020:
*---------------------------------------------------------------*
* entry is a directory *
*---------------------------------------------------------------*
bsr dodir ;process input directory
tst.l d0 ;Q. Good return?
bne.s parg_err ;A. no - quit
parg030:
lea anchor(a5),a0 ;search anchor
move.l arpbase(a5),a6
* rc = FindNext(chain)
* d0 a0
CALL FindNext(a6)
tst.l d0
beq.s parg010 ;loop on if next entry
*---------------------------------------------------------------*
* End of chain - we are done with this argument *
*---------------------------------------------------------------*
lea anchor(a5),a0 ;point to anchor
move.l arpbase(a5),a6 ;ARP base
* FreeAnchorChain(chain)
* a0
CALL FreeAnchorChain(a6)
clr.l d0 ;return code
rts
parg_err:
moveq.l #20,d0 ;set error return code
rts
PAGE
*****************************************************************
* Section Name: dodir *
* *
* Function: Processes a file directory included in the *
* input argument list *
* *
* Entry Data: fname(a5) contains the full path of the *
* directory *
* *
* Exit Data: d0 - return code (0 = success) *
* *
* NOTE: This routine uses the AmigaDOS Examine/ExNext *
* functions, since wild cards are not needed *
* *
*****************************************************************
dodir:
movem.l d2-d3/a3-a4,-(a7) ;save registers
lea dirbuf(a5),a0 ;buffer area to build file names
lea fname(a5),a1 ;path name of directory
1$: move.b (a1)+,(a0)+ ;move directory name to buffer
bne.s 1$ ;stop at null
lea -2(a0),a0 ;point at last character
move.b (a0)+,d0 ;inspect last character
cmp.b #':',d0 ;Q. Is last character ':'?
beq.s ddir010 ;A. yes - don't append a /
move.b #'/',(a0)+ ; no - append a / for path name
ddir010:
move.l a0,a4 ;save beginning address for file name
*---------------------------------------------------------------*
* Allocate memory for local FIB *
*---------------------------------------------------------------*
move.l #fib_SIZEOF,d0 ;size of fib
move.l #MEMF_CLEAR,d1 ;allocation type
move.l Absbase,a6 ;Exec base
* *ptr = AllocMem(size,type)
* d0 d0 d1
CALL AllocMem(a6) ;allocate fib
tst.l d0 ;Q. Allocation successful?
bne.s ddir020 ;A. yes - continue
*---------------------------------------------------------------*
* Unable to allocate FIB - gotta quit *
*---------------------------------------------------------------*
move.l stdout(a5),d1 ;Std Output file handle
lea nomem(pc),a0
move.l a0,d2 ;address message
move.l #nomeml,d3 ;length of it.
move.l dosaddr(a5),a6 ;DOSBase into a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
bra ddir_err ;and leave
ddir020:
move.l d0,a3 ;save pointer to FIB
*---------------------------------------------------------------*
* Obtain a lock on directory *
*---------------------------------------------------------------*
lea fname(a5),a0 ;point to directory name
move.l a0,d1
move.l #ACCESS_READ,d2 ;get a shared lock
move.l dosaddr(a5),a6
* Lock = Lock(name,accessMode)
* d0 d1 d2
CALL Lock(a6)
tst.l d0 ;Q. Lock obtained?
bne.s ddir030 ;A. yes - continue
lea fname(a5),a0
move.l a0,work(a5) ;build argument list
lea work(a5),a1 ;point to argument list
lea dlokerr(pc),a0 ;printf pattern
move.l arpbase(a5),a6
* Printf(string,*args)
* a0 a1
CALL Printf(a6)
bra ddir_err ;and leave
ddir030:
move.l d0,d3 ;save lock
*---------------------------------------------------------------*
* Walk the directory chain, using Examine/ExNext *
*---------------------------------------------------------------*
move.l d3,d1 ;lock
move.l a3,d2 ;pointer to fib
move.l dosaddr(a5),a6
* success = Examine(lock,fib)
* d0 d1 d2
CALL Examine(a6)
tst.l d0 ;Q. Successful?
bne.s ddir040 ;A. yes - continue
lea fname(a5),a0
move.l a0,work(a5) ;build argument list
lea work(a5),a1 ;point to argument list
lea dexerr(pc),a0 ;printf pattern
move.l arpbase(a5),a6
* Printf(string,*args)
* a0 a1
CALL Printf(a6)
bra ddir_err ;and leave
ddir040:
*---------------------------------------------------------------*
* If entry is for a directory skip it *
* NOTE: The program will NOT recursively walk a nested *
* directory structure *
*---------------------------------------------------------------*
move.l fib_DirEntryType(a3),d0 ;file or directory indicator
bpl.s ddir050 ; >= 0 ==> directory - bypass it
*---------------------------------------------------------------*
* Entry is a file - build full file name *
*---------------------------------------------------------------*
move.l a4,a0 ;point to file path
lea fib_FileName(a3),a1 ;point to file name
1$: move.b (a1)+,(a0)+ ;append file name to path
bne.s 1$ ;loop until null byte
*---------------------------------------------------------------*
* Now process the file *
*---------------------------------------------------------------*
move.l a3,a0 ;point to FIB
lea dirbuf(a5),a1 ;point to path name
bsr dofile ;process file
tst.l d0 ;Q. Success?
beq.s ddir050 ;A. yes - continue
*---------------------------------------------------------------*
* Error - free local resources and exit *
*---------------------------------------------------------------*
move.l a3,a1 ;address of fib
move.l #fib_SIZEOF,d0 ;length of fib
move.l Absbase,a6 ;exec library
* FreeMem(area,size);
* a1 d0
CALL FreeMem(a6) ;free work area
move.l d3,d1 ;lock
move.l dosaddr(a5),a6
* UnLock(lock)
* d1
CALL UnLock(a6) ;free lock
bra.s ddir_err
ddir050:
*---------------------------------------------------------------*
* Get next entry in directory *
*---------------------------------------------------------------*
move.l d3,d1 ;lock
move.l a3,d2 ;pointer to FIB
move.l dosaddr(a5),a6
* success = ExNext(lock,fib)
* d0 d1 d2
CALL ExNext(a6)
tst.l d0 ;Q. Success?
bne.s ddir040 ;A. yes - loop on to process this entry
*---------------------------------------------------------------*
* Insure that error is NO_MORE_ENTRIES *
*---------------------------------------------------------------*
move.l dosaddr(a5),a6
* error = IoErr()
* d0
CALL IoErr(a6) ;get DOS error code
move.l d0,-(a7) ;save error code on stack
*---------------------------------------------------------------*
* Free Resources *
*---------------------------------------------------------------*
move.l a3,a1 ;address of fib
move.l #fib_SIZEOF,d0 ;length of fib
move.l Absbase,a6 ;exec library
* FreeMem(area,size);
* a1 d0
CALL FreeMem(a6) ;free work area
move.l d3,d1 ;lock
move.l dosaddr(a5),a6
* UnLock(lock)
* d1
CALL UnLock(a6) ;free lock
move.l (a7)+,d0 ;pop DOS error code
cmp.l #ERROR_NO_MORE_ENTRIES,d0 ;Q. Expected 'error' value?
beq.s ddir060 ;yes - ok to return
move.l d0,work(a5) ;no - put error code in arg list
lea work(a5),a1 ;point to arg list
lea baddir(pc),a0 ;Printf pattern
move.l arpbase(a5),a6
* Printf(string,*args)
* a0 a1
CALL Printf(a6) ;print error message
bra.s ddir_err ;take error exit
ddir060:
movem.l (a7)+,d2-d3/a3-a4 ;restore registers
clr.l d0 ;good return code
rts
ddir_err:
movem.l (a7)+,d2-d3/a3-a4 ;restore registers
moveq.l #20,d0 ;error return code
rts
PAGE
*****************************************************************
* Section Name: dofile *
* *
* Function: Processes a file included in the input *
* argument list *
* *
* Entry Data: a0 - FIB for file *
* a1 - full path name for file *
* *
* Exit Data: d0 - return code (0 = success) *
* *
*****************************************************************
dofile:
movem.l d2-d5/a2-a4,-(a7) ;save registers
move.l a0,a3 ;save FIB pointer
move.l a1,a4 ;save name pointer
*---------------------------------------------------------------*
* Construct full path name for output file *
*---------------------------------------------------------------*
lea fib_FileName(a0),a1 ;point to file name of input
move.l outfnam(a5),a0 ;point into buffer containing output path
1$: move.b (a1)+,(a0)+ ;append file name to path
bne.s 1$ ;loop until null-byte
*---------------------------------------------------------------*
* Get date for comparison *
*---------------------------------------------------------------*
bsr getcdate ;get datestamp for compare
tst.l d0 ;Q. Good return?
bne dofl_err ;A. No - quit now
lea cmpdate(a5),a0 ;point to compare date stamp
lea fib_DateStamp(a3),a1 ;point to FIB date stamp
moveq.l #2,d0 ;loop count - 3 long words
dofl010:
move.l (a0)+,d1 ;next long word from compare date
cmp.l (a1)+,d1 ;compare to next long word from FIB
blt.s dofl020 ;branch if FIB datestamp is higher
bgt dofl090 ;if FIB datestamp lower - do not process
dbra d0,dofl010 ;check entire DateStamp
bra dofl090 ;FIB date is equal to - skip file
dofl020:
*---------------------------------------------------------------*
* File is to be processed - tell user *
*---------------------------------------------------------------*
move.l a4,work(a5) ;build argument list
lea work(a5),a1 ;point to argument list
lea fline(pc),a0 ;printf pattern
move.l arpbase(a5),a6
* Printf(string,*args)
* a0 a1
CALL Printf(a6)
*---------------------------------------------------------------*
* Open Input file *
*---------------------------------------------------------------*
move.l a4,d1 ;pointer to file name
move.l #MODE_OLDFILE,d2 ;access mode
move.l dosaddr(a5),a6
* file = Open(name,accessMode)
* d0 d1 d2
CALL Open(a6) ;Open input file
tst.l d0 ;Q. open successful?
bne.s dofl030 ;A. yes - continue
*---------------------------------------------------------------*
* Input file failed to open - inform user and exit *
*---------------------------------------------------------------*
lea iopnerm(pc),a0
move.l a0,d2 ;Set up and write err msg to console
move.l #iopnerl,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,size)
* d1 d2 d3
CALL Write(a6)
bra dofl_err
dofl030:
move.l d0,d4 ;save input file handle
*---------------------------------------------------------------*
* Open output file *
*---------------------------------------------------------------*
lea outbuf(a5),a0 ;point to output file path/name
move.l a0,d1 ;pointer to file name
move.l #MODE_NEWFILE,d2 ;access mode
move.l dosaddr(a5),a6
* file = Open(name,accessMode)
* d0 d1 d2
CALL Open(a6) ;Open output file
tst.l d0 ;Q. open successful?
bne.s dofl040 ;A. yes - continue
*---------------------------------------------------------------*
* Output file failed to open - inform user and exit *
*---------------------------------------------------------------*
lea oopnerm(pc),a0
move.l a0,d2 ;Set up and write err msg to console
move.l #oopnerl,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,size)
* d1 d2 d3
CALL Write(a6)
move.l d4,d1 ;Close Input file
move.l dosaddr(a5),a6
* Close(file)
* d1
CALL Close(a6)
bra.s dofl_err
dofl040:
move.l d0,d5 ;save output file handle
move.l d4,d1 ;input file handle in d1
bsr copyfile ;copy the files
move.l d0,-(a7) ;save copy return code
*---------------------------------------------------------------*
* Close the files *
*---------------------------------------------------------------*
move.l d5,d1 ;Output file handle
move.l dosaddr(a5),a6
* Close(file)
* d1
CALL Close(a6) ;close output file
move.l d4,d1 ;Input file handle
move.l dosaddr(a5),a6
* Close(file)
* d1
CALL Close(a6) ;close input file
move.l (a7)+,d0 ;restore return code from copy
tst.l d0 ;Q. Good return from copy?
bne.s dofl_err ;A. no - quit
*---------------------------------------------------------------*
* Set DateStamp of output file to match input *
*---------------------------------------------------------------*
move.l a3,a0 ;FIB of input file
bsr setdate ;call set date routine
lea foklin(pc),a0
move.l a0,d2 ;Set up and write ok msg to console
move.l #foklinl,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6)
dofl090:
clr.l d0
movem.l (a7)+,d2-d5/a2-a4 ;restore registers
rts
dofl_err:
moveq.l #20,d0 ;set error return code
movem.l (a7)+,d2-d5/a2-a4 ;restore registers
rts
PAGE
*****************************************************************
* Section Name: getcdate *
* *
* Function: Obtains the datestamp of the corresponding *
* output file (if since option not used) *
* *
* Entry Data: outbuf(a5) contains full path name of *
* output file *
* *
* Exit Data: cmpdate(a5) will contain the date for *
* comparison *
* d0 - return code (0 = success) *
* *
* NOTE: if 'since' option was specified, this routine *
* will just return. The cmpdate field has already*
* been populated with the correct date *
* *
*****************************************************************
getcdate:
tst.l sinfil(a5) ;Q. SINCE file specified?
beq.s gcdt010 ;A. No - proceed
clr.l d0 ;A. yes - set good return code
rts ; and return
gcdt010:
movem.l d2-d4,-(a7) ;save work registers
*---------------------------------------------------------------*
* Obtain a lock on the output file - if file does not exist *
* this will fail. In this case, set cmpdate to zeros so the *
* comparison will result in the file being processed *
*---------------------------------------------------------------*
lea outbuf(a5),a0 ;point to output file path/name
move.l a0,d1
move.l #ACCESS_READ,d2 ;get a shared lock
move.l dosaddr(a5),a6
* Lock = Lock(name,accessMode)
* d0 d1 d2
CALL Lock(a6)
tst.l d0 ;Q. Lock obtained?
bne.s gcdt020 ;A. yes - continue
lea cmpdate(a5),a0 ;A. no - point to compare date
moveq.l #2,d0 ;loop control - set 3 longwords to 0
1$: clr.l (a0)+ ;set datestamp to 0's
dbra d0,1$ ; for 3 long words
movem.l (a7)+,d2-d4 ;restore registers
clr.l d0 ;set good return code
rts ;and return
gcdt020:
*---------------------------------------------------------------*
* Now get File Info for file *
*---------------------------------------------------------------*
move.l d0,d4 ;save Lock
move.l d0,d1 ;lock in d1
lea fib(a5),a0 ;point to work fib
move.l a0,d2 ;FIB pointer in d2
move.l dosaddr(a5),a6
* success = Examine(lock,FIB)
* d0 d1 d2
CALL Examine(a6)
move.l d0,-(a7) ;save Examine return code on stack
*---------------------------------------------------------------*
* Free the lock obtained above *
*---------------------------------------------------------------*
move.l d4,d1 ;lock into d1
move.l dosaddr(a5),a6
* UnLock(lock)
* d1
CALL UnLock(a6) ;free the lock
move.l (a7)+,d0 ;restore Examine return code from stack
tst.l d0 ;Q. Success?
beq gcdt_err ;A. No - examine failed
lea fib(a5),a0 ;point to fib
lea fib_DateStamp(a0),a1 ;point to file's datestamp
lea cmpdate(a5),a0 ;point to comparison datestamp
moveq.l #2,d0 ;loop control - move 3 long words
1$: move.l (a1)+,(a0)+ ;move file's datestamp to compare field
dbra d0,1$ ; move all 3 long words
movem.l (a7)+,d2-d4 ;restore registers
clr.l d0 ;good return code
rts ; return to caller
gcdt_err:
lea exerm(pc),a0
move.l a0,d2 ;Set up and write err msg to console
move.l #exerl,d3
move.l stdout(a5),d1
move.l dosaddr(a5),a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6)
movem.l (a7)+,d2-d4 ;restore registers
moveq.l #20,d0 ;set bad return code
rts ;and return
PAGE
*****************************************************************
* Section Name: copyfile *
* *
* Function: Copies input file to output file *
* *
* Entry Data: d0 - file handle for (opened) output file *
* d1 - file handle for (opened) input file *
* *
* Exit Data: d0 - return code (0 = success) *
* *
*****************************************************************
copyfile:
movem.l d3-d6/a2-a4,-(a7) ;save registers
move.l d0,d4 ;save output file handle
move.l d1,d5 ;save input file handle
move.l databuf(a5),d0 ;address of data buffer
bne.s cpfl010 ;bypass alloc if buffer exists
*---------------------------------------------------------------*
* Allocate work buffer for reading/writing *
*---------------------------------------------------------------*
move.l #RW_BUFS,d0 ;size of buffer
move.l #MEMF_CLEAR,d1 ;allocation type
move.l Absbase,a6 ;Exec base
* *ptr = AllocMem(size,type)
* d0 d0 d1
CALL AllocMem(a6) ;allocate buffer
move.l d0,databuf(a5) ;save and test address
bne cpfl010 ;continue if alloc successful
*---------------------------------------------------------------*
* Unable to allocate buffer - gotta quit *
*---------------------------------------------------------------*
move.l stdout(a5),d1 ;Std Output file handle
lea nomem(pc),a0
move.l a0,d2 ;address message
move.l #nomeml,d3 ;length of it.
move.l dosaddr(a5),a6 ;DOSBase into a6
* Write(file,data,length)
* d1 d2 d3
CALL Write(a6) ;Send message to standard out
bra cpfl_err ;and leave
cpfl010:
*---------------------------------------------------------------*
* Read input file *
*---------------------------------------------------------------*
move.l d5,d1 ;input file handle
move.l databuf(a5),d2 ;address of buffer
move.l #RW_BUFS,d3 ;max length to read
move.l dosaddr(a5),a6
* actualLength = Read(file,buffer,maxLength)
* d0 d1 d2 d3
CALL Read(a6)
move.l d0,d6 ;save actual length read
beq cpfl090 ;0 ==> end-of-file
bpl.s cpfl020 ; > 0 data read OK
*---------------------------------------------------------------*
* A Read error has occured *
*---------------------------------------------------------------*
move.l dosaddr(a5),a6
* error = IoErr()
* d0
CALL IoErr(a6) ;get actual error value
move.l d0,work(a5) ;store in parm list for Printf
lea rderrm(pc),a0 ;string pattern
lea work(a5),a1 ;arg array
move.l arpbase(a5),a6
* count = Printf(*string,*arg-array)
* d0 a0 a1
CALL Printf(a6) ;write error message
bra.s cpfl_err ;take error exit
cpfl020:
*---------------------------------------------------------------*
* Write same data to output file *
*---------------------------------------------------------------*
move.l d4,d1 ;output file handle
move.l databuf(a5),d2 ;buffer address
move.l d6,d3 ;length of data read
move.l dosaddr(a5),a6
* returnedLength = Write(file,buffer,length);
* d0 d1 d2 d3
CALL Write(a6) ;write data to output file
cmp.l d0,d6 ;Q. did we write all the data?
beq.s cpfl010 ;A. YES - loop on for rest of data
*---------------------------------------------------------------*
* An error occurred writing, since not all data was written *
*---------------------------------------------------------------*
move.l dosaddr(a5),a6
* error = IoErr()
* d0
CALL IoErr(a6) ;get actual error value
move.l d0,work(a5) ;store in parm list for Printf
lea wrerrm(pc),a0 ;string pattern
lea work(a5),a1 ;arg array
move.l arpbase(a5),a6
* count = Printf(*string,*arg-array)
* d0 a0 a1
CALL Printf(a6) ;write error message
cpfl_err:
movem.l (a7)+,d3-d6/a2-a4 ;restore registers
moveq.l #20,d0 ;error return code
rts ;return to caller
cpfl090:
movem.l (a7)+,d3-d6/a2-a4 ;restore registers
clr.l d0 ;good return code
rts ;return
PAGE
*****************************************************************
* Section Name: getfib *
* *
* Function: Gets the FileInfoBlock for the passed *
* named file *
* *
* Entry Data: a5 - Address of global work area *
* a0 - address of file name string *
* *
* Exit Data: d0 - return code (0 = success) *
* fib(a5) - filled in File Info block *
* *
*****************************************************************
getfib:
movem.l d2/d3,-(a7) ;save registers
*---------------------------------------------------------------*
* Get a shared lock on the file *
*---------------------------------------------------------------*
move.l a0,d1 ;file name in d1
move.l #ACCESS_READ,d2 ;lock type
move.l dosaddr(a5),a6 ;DOSBase
* lock = Lock(name,mode)
* d0 d1 d2
CALL Lock(a6)
tst.l d0 ;Q. Lock obtained?
beq.s gfib_err ;A. No - return error
move.l d0,d3 ;save lock
*---------------------------------------------------------------*
* now get File Info from lock *
*---------------------------------------------------------------*
move.l d3,d1 ;lock in d1
lea fib(a5),a0 ;address fib
move.l a0,d2 ;FIB address in d2
move.l dosaddr(a5),a6
* boolean = Examine(lock,&FileInfoBlock);
* d0 d1 d2
CALL Examine(a6)
move.l d0,-(a7) ;save Examine return code
*---------------------------------------------------------------*
* Free Lock (we are done with it) *
*---------------------------------------------------------------*
move.l d3,d1 ;lock in d1
move.l dosaddr(a5),a6
* UnLock(lock);
* d1
CALL UnLock(a6) ;free lock
move.l (a7)+,d0 ;restore return code from examine
tst.l d0 ;Q. Good return from Examine?
beq.s gfib_err ;A. no - take error exit
*---------------------------------------------------------------*
* Successful processing *
*---------------------------------------------------------------*
clr.l d0 ;set good return code
movem.l (a7)+,d2/d3 ;restore registers
rts ;and return
*---------------------------------------------------------------*
* Error exit *
*---------------------------------------------------------------*
gfib_err:
moveq.l #20,d0 ;set bad return code
movem.l (a7)+,d2/d3 ;restore registers
rts ;and return
PAGE
*****************************************************************
* Section Name: setdate *
* *
* Function: Sets the datestamp for the output file *
* to match that contained in the input FIB *
* *
* Entry Data: outbuf(a5) contains full path name of *
* output file *
* a0 - the address of the input file's FIB *
* *
* Exit Data: N/A (Note: errors are considered non- *
* critical and are ignored) *
*****************************************************************
setdate:
movem.l d3/d4/a3/a4,-(a7) ;save registers
move.l a0,a3 ;save address of fib
*---------------------------------------------------------------*
* Get Handler Process address *
*---------------------------------------------------------------*
lea outbuf(a5),a0 ;get output file name
move.l a0,d1
move.l dosaddr(a5),a6
* process - DeviceProc(name)
* d0 d1
CALL DeviceProc(a6)
tst.l d0 ;Q. Handler found?
beq.s sdat090 ;A. no - can't continue
move.l d0,a4 ; yes - save handler address
*---------------------------------------------------------------*
* Get a lock on the output file *
*---------------------------------------------------------------*
lea outbuf(a5),a0 ;name of output file
move.l a0,d1
move.l #ACCESS_READ,d2 ;lock type (shared)
move.l dosaddr(a5),a6
* lock = Lock(name,accessMode)
* d0 d1 d2
CALL Lock(a6)
tst.l d0 ;Q. Lock obtained?
beq.s sdat090 ;A. No - cannot continue
move.l d0,-(a7) ; yes - save lock on stack
*---------------------------------------------------------------*
* Get lock for parent directory *
*---------------------------------------------------------------*
move.l d0,d1 ;lock into d1
* lock = ParentDir(lock)
* d0 d1
CALL ParentDir(a6)
move.l d0,d3 ;save lock (note: this CAN be zero)
*---------------------------------------------------------------*
* Free the first lock we obtained - don't need it any more *
*---------------------------------------------------------------*
move.l (a7)+,d1 ;lock for output file
* UnLock(lock)
* d1
CALL UnLock(a6) ;free this lock
*---------------------------------------------------------------*
* Now build the file name as a BCPL string *
* NOTE: this name MUST NOT include any path information, *
* just the file name *
*---------------------------------------------------------------*
lea strwork+1(a5),a0 ;string work area (saving the 1st byte)
lea fib_FileName(a3),a1 ;file name in passed FIB
clr.l d0 ;set count to 0
1$: addq.b #1,d0 ;increment count
move.b (a1)+,(a0)+ ;move byte
bne.s 1$ ;loop until null byte
subq.b #1,d0 ;don't count null byte
move.b d0,strwork(a5) ;length into first byte
*---------------------------------------------------------------*
* Build Argument list for DOS Packet *
*---------------------------------------------------------------*
clr.l pktarg0(a5) ;first argument null
move.l d3,pktarg1(a5) ;second argument is lock of parent dir
lea strwork(a5),a0 ;pointer to BSTR file name
move.l a0,d0
lsr.l #2,d0 ;convert to BCPL pointer (BPTR)
move.l d0,pktarg2(a5) ;third argument is BSTR pointer to file name
lea fib_DateStamp(a3),a0
move.l a0,pktarg3(a5) ;fourth arg is REAL pointer to DateStamp
*---------------------------------------------------------------*
* Now use the ARP routine to send the DOS Packet *
*---------------------------------------------------------------*
move.l #ACTION_SET_DATE,d0
lea pktarg0(a5),a0
move.l a4,a1 ;handler process
move.l arpbase(a5),a6
* Result1 = SendPacket(action, args, handler)
* d0 d0 a0 a1
CALL SendPacket(a6)
*---------------------------------------------------------------*
* ignore return code - if it worked, it worked - if not, not *
* *
* Free the lock on the Parent Directory *
*---------------------------------------------------------------*
move.l d3,d1
move.l dosaddr(a5),a6
* UnLock(lock)
* d1
CALL UnLock(a6)
sdat090:
movem.l (a7)+,d3/d4/a3/a4 ;restore registers
rts
PAGE
*---------------------------------------------------------------*
* Program Constants *
*---------------------------------------------------------------*
dosname dc.b 'dos.library',0
arpname dc.b 'arp.library',0
CNOP 0,4
nomem dc.b 'Unable to allocate work area - aborted',$0a
nomeml EQU *-nomem
noarp dc.b 'Unable to Open ARP Library - aborted',$0a
noarpl EQU *-noarp
nosinm dc.b 'Unable to locate SINCE file - aborted',$0a
nosinml EQU *-nosinm
noout dc.b 'Unable to locate TO directory - aborted',$0a
nooutl EQU *-noout
notdir dc.b 'Specified TO parameter is not a directory - aborted',$0a
notdirl EQU *-notdir
templ dc.b 'FROM/A,,,,,,,,,,,,TO/A/K,SINCE/K',0
cmdpr dc.b 'Usage: ',$9b,'1;32mUpdate',$9b,'0;31m [FROM] ',$9b,'1;32mobj1 '
dc.b $9b,'0;31m[obj2 ... obj12] ',$9b,'1;32mTO dir',$9b
dc.b '0;31m [SINCE mfile]',$0a,$0a
dc.b ' Where ',$9b,'1mobj1...obj12',$9b,'0m are either files '
dc.b 'or directories (with or without',$0a
dc.b ' wildcards, specifying input files to be checked'
dc.b $0a,$0a
dc.b ' ',$9b,'1mdir',$9b,'0m is the output directory '
dc.b 'to receive the qualifying files',$0a,$0a
dc.b ' and ',$9b,'1mmfile',$9b,'0m specifies the '
dc.b 'optional file whose datestamp will be ',$0a
dc.b ' used to determine which input files '
dc.b 'will updated in the ',$0a
dc.b ' output directory - NOTE that if no SINCE '
dc.b 'file is specified,',$0a
dc.b ' the corresponding file in the TO directory '
dc.b 'will be checked',$0a,0
ferrm dc.b 'Command format error',$0a
ferrml EQU *-ferrm
fline dc.b '... %s ',0
foklin dc.b ' copied',$0a
foklinl EQU *-foklin
iopnerm dc.b ' Unable to Open Input file - Aborted',$0a
iopnerl EQU *-iopnerm
oopnerm dc.b ' Unable to Open Output file - Aborted',$0a
oopnerl EQU *-oopnerm
exerm dc.b ' Error examining output file after locking - Aborted',$0a
exerl EQU *-exerm
rderrm dc.b ' Read Error - code %ld',$0a,0
wrerrm dc.b ' Write Error - code %ld',$0a,0
dlokerr dc.b ' Unable to Lock Input directory %s - Aborted',$0a,0
dexerr dc.b ' Unable to Examine Input directory %s - Aborted',$0a,0
baddir dc.b ' Corrupted Directory chain - error %ld - Aborted',$0a,0
CNOP 0,4
PAGE
*---------------------------------------------------------------*
* Work Area *
* Note: the following areas are actually obtained by an Alloc- *
* Mem system call, and addressed relative to register a5 *
*---------------------------------------------------------------*
OFFSET 0
cmdline ds.l 1 ;pointer to command line
cmdlen ds.l 1 ;length of command line
dosaddr ds.l 1 ;address of DOSBase
arpbase ds.l 1 ;address of ArpBase
stdout ds.l 1 ;file handle of std output
databuf ds.l 1 ;pointer to 16K data buffer for copying files
argv ds.l 12 ;argument vectors for input names (FROM)
todir ds.l 1 ;arg vector for TO keyword
sinfil ds.l 1 ;arg vector for SINCE file
cmpdate ds.l 3 ;DateStamp for compare
work ds.l 1 ;work word (for printf)
outfnam ds.l 1 ;pointer into outbuf for file name
pktargs ds.l 7 ;arg array for DOS Packets
pktarg0 EQU pktargs
pktarg1 EQU pktargs+4
pktarg2 EQU pktargs+8
pktarg3 EQU pktargs+12
argc ds.w 1 ;argument count (max 64)
CNOP 0,4
fib ds.b fib_SIZEOF ;work FileInfoBlock
CNOP 0,4
anchor ds.b AP_SIZEOF ;arp w/c file search anchor
fname ds.b 128 ;buffer for arp to build file name
CNOP 0,4
outbuf ds.b 128 ;buffer for output file path name
dirbuf ds.b 128
strwork ds.b 128 ;buffer for BSTR conversion
wk_lgth equ *
END